from sys import argv
from math import sin, cos
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

class MyPyOpenGLTest:
    def __init__(self, width=640, height=480, title='雾效'):
        glutInit(len(argv), argv)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        glutInitWindowSize(width, height)
        glutInitWindowPosition(350, 200)
        self.window = glutCreateWindow(title.encode('gbk'))
        glutDisplayFunc(self.draw)
        glutSpecialFunc(self.special_key)
        # 三维物体的z坐标
        self.z = -5
        # 绕y轴的旋转角度
        self.angle = 0
        self.fog_background_color = (0.5, 0.5, 0.5, 1)
        # 默认使用线性雾效
        self.fog_mode = GL_LINEAR
        
        # 初始化窗口背景为灰色，与雾的颜色相同
        glClearColor(*self.fog_background_color)
        # 深度测试
        glEnable(GL_DEPTH_TEST)
        
        glShadeModel(GL_SMOOTH)
        # 对点进行反走样，会显示为圆形的点
        glEnable(GL_POINT_SMOOTH)
        glEnable(GL_LINE_SMOOTH)
        glEnable(GL_POLYGON_SMOOTH)        
        glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
        glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST)

        # 创建与鼠标右键关联的弹出式菜单
        self.create_menu()

        glLightfv(GL_LIGHT0,GL_POSITION,  (0, 3, 3, 0))
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)

        glMaterialfv(GL_FRONT, GL_AMBIENT, (0.15, 0.23, 0.13))
        glMaterialfv(GL_FRONT, GL_DIFFUSE, (0.15, 0.23, 0.13))
        glMaterialfv(GL_FRONT, GL_SPECULAR, (0.15, 0.23, 0.13))

        glMatrixMode(GL_PROJECTION)
        gluPerspective(45, width/height, 0.1, 100)
        glMatrixMode(GL_MODELVIEW)

    def process_menu(self, value):
        if value == 0:
            self.fog_mode = value
        elif value == 11:
            self.fog_mode = GL_LINEAR
        elif value == 12:
            self.fog_mode = GL_EXP
        elif value == 13:
            self.fog_mode = GL_EXP2
        return value

    def create_menu(self):
        # 创建子菜单
        sub_menu = glutCreateMenu(self.process_menu)
        glutAddMenuEntry('线性雾效'.encode('gbk'), 11)
        glutAddMenuEntry('指数雾效'.encode('gbk'), 12)
        glutAddMenuEntry('指数雾效2'.encode('gbk'), 13)
        # 创建主菜单
        main_menu = glutCreateMenu(self.process_menu)
        glutAddMenuEntry('关闭雾效'.encode('gb18030'), 0)
        # 添加子菜单
        glutAddSubMenu('开启雾效'.encode('gbk'), sub_menu)
        glutAttachMenu(GLUT_RIGHT_BUTTON)

    def special_key(self, key, x, y):
        # 通过上下按键沿z轴移动茶壶，左右按键绕y轴旋转茶壶
        if key == GLUT_KEY_UP:
            # 远离视点
            self.z = self.z - 0.05
        elif key == GLUT_KEY_DOWN:
            # 靠近视点
            self.z = self.z + 0.05
        elif key == GLUT_KEY_LEFT:
            self.angle = self.angle - 5
        elif key == GLUT_KEY_RIGHT:
            self.angle = self.angle + 5
        # 每次按键之后强制刷新屏幕
        glutPostRedisplay()
        
    def draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        if self.fog_mode == 0:
            glDisable(GL_FOG)
        else:
            glEnable(GL_FOG)
            glFogi(GL_FOG_MODE,self.fog_mode)
            glFogfv(GL_FOG_COLOR, self.fog_background_color)
            glFogf(GL_FOG_DENSITY, 0.35)
            glHint(GL_FOG_HINT,GL_DONT_CARE)
            glFogf(GL_FOG_START, 1)
            glFogf(GL_FOG_END, 10)
        
        # 绘制实体茶壶
        glTranslate(0, 0, self.z)
        glRotate(self.angle, 0, 1, 0)
        glutSolidTeapot(0.8)
        
        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()

if __name__ == '__main__':
    MyPyOpenGLTest().mainloop()
